功能 您所在的位置:网站首页 配置 Vite Vite 官方中文文档 功能

功能

2024-05-20 22:50| 来源: 网络整理| 查看: 265

# 功能

对非常基础的使用来说,使用 Vite 开发和使用一个静态文件服务器并没有太大区别。然而,Vite 还通过原生 ESM 导入提供了许多主要用于打包场景的增强功能。

# NPM 依赖解析和预构建

原生 ES 导入不支持下面这样的裸模块导入:

import { someMethod } from 'my-dep'

上面的代码会在浏览器中抛出一个错误。Vite 将会检测到所有被加载的源文件中的此类裸模块导入,并执行以下操作:

预构建 它们可以提高页面加载速度,并将 CommonJS / UMD 转换为 ESM 格式。预构建这一步由 esbuild 执行,这使得 Vite 的冷启动时间比任何基于 JavaScript 的打包器都要快得多。

重写导入为合法的 URL,例如 /node_modules/.vite/deps/my-dep.js?v=f3sf2ebd以便浏览器能够正确导入它们。

依赖是强缓存的

Vite 通过 HTTP 头来缓存请求得到的依赖,所以如果你想要编辑或调试一个依赖,请按照 这里 的步骤操作。

# 模块热替换

Vite 提供了一套原生 ESM 的 HMR API 。 具有 HMR 功能的框架可以利用该 API 提供即时、准确的更新,而无需重新加载页面或清除应用程序状态。Vite 内置了 HMR 到 Vue 单文件组件(SFC) 和 React Fast Refresh 中。也通过 @prefresh/vite 对 Preact 实现了官方集成。

注意,你不需要手动设置这些 —— 当你通过 create-vite 创建应用程序时,所选模板已经为你预先配置了这些。

# TypeScript

Vite 天然支持引入 .ts文件。

# 仅执行转译

请注意,Vite 仅执行 .ts文件的转译工作,并不执行任何类型检查。并假定类型检查已经被你的 IDE 或构建过程处理了。

Vite 之所以不把类型检查作为转换过程的一部分,是因为这两项工作在本质上是不同的。转译可以在每个文件的基础上进行,与 Vite 的按需编译模式完全吻合。相比之下,类型检查需要了解整个模块图。把类型检查塞进 Vite 的转换管道,将不可避免地损害 Vite 的速度优势。

Vite 的工作是尽可能快地将源模块转化为可以在浏览器中运行的形式。为此,我们建议将静态分析检查与 Vite 的转换管道分开。这一原则也适用于其他静态分析检查,例如 ESLint。

在构建生产版本时,你可以在 Vite 的构建命令之外运行 tsc --noEmit。

在开发时,如果你需要更多的 IDE 提示,我们建议在一个单独的进程中运行 tsc --noEmit --watch,或者如果你喜欢在浏览器中直接看到上报的类型错误,可以使用 vite-plugin-checker 。

Vite 使用 esbuild 将 TypeScript 转译到 JavaScript,约是 tsc速度的 20~30 倍,同时 HMR 更新反映到浏览器的时间小于 50ms。

使用 仅含类型的导入和导出 形式的语法可以避免潜在的 “仅含类型的导入被不正确打包” 的问题,写法示例如下:

import type { T } from 'only/types' export type { T } # TypeScript 编译器选项

tsconfig.json中 compilerOptions下的一些配置项需要特别注意。

# isolatedModules¶ (opens new window)

应该设置为 true。

这是因为 esbuild只执行没有类型信息的转译,它并不支持某些特性,如 const enum和隐式类型导入。

你必须在 tsconfig.json中的 compilerOptions下设置 "isolatedModules": true。如此做,TS 会警告你不要使用隔离(isolated)转译的功能。

然而,一些库(如:vue (opens new window) )不能很好地与 "isolatedModules": true共同工作。你可以在上游仓库修复好之前暂时使用 "skipLibCheck": true来缓解这个错误。

# useDefineForClassFields¶ (opens new window)

从 Vite v2.5.0 开始,如果 TypeScript 的 target 是 ESNext或 ES2022及更新版本,此选项默认值则为 true。这与 tsc v4.3.2 及以后版本的行为 一致。这也是标准的 ECMAScript 的运行时行为。

但对于那些习惯其他编程语言或旧版本 TypeScript 的开发者来说,这可能是违反直觉的。 你可以参阅 TypeScript 3.7 发布日志 中了解更多关于如何兼容的信息。

如果你正在使用一个严重依赖 class fields 的库,请注意该库对此选项的预期设置。

大多数库都希望 "useDefineForClassFields": true,如 MobX ,Vue Class Components 8.x (opens new window) 等。

但是有几个库还没有兼容这个新的默认值,其中包括 lit-element 。如果遇到这种情况,请将 useDefineForClassFields设置为 false。

# 影响构建结果的其他编译器选项 extends importsNotUsedAsValues preserveValueImports jsxFactory jsxFragmentFactory

如果你的代码库很难迁移到 "isolatedModules": true,或许你可以尝试通过第三方插件来解决,比如 rollup-plugin-friendly-type-imports 。但是,这种方式不被 Vite 官方支持。

# 客户端类型

Vite 默认的类型定义是写给它的 Node.js API 的。要将其补充到一个 Vite 应用的客户端代码环境中,请添加一个 d.ts声明文件:

///

同时,你也可以将 vite/client添加到 tsconfig中的 compilerOptions.types下:

{ "compilerOptions": { "types": ["vite/client"] } }

这将会提供以下类型定义补充:

资源导入 (例如:导入一个 .svg文件) importa.env上 Vite 注入的环境变量的类型定义 importa.hot上的 HMR API 类型定义

TIP

要覆盖默认的类型定义,请添加一个包含你所定义类型的文件,请在三斜线注释 reference vite/client前添加定义。

例如,要为 React 组件中的 *.svg文件定义类型:

vite-env-override.d.ts(the file that contains your typings): declare module '*.svg' { const content: React.FC export default content } The file containing the reference to vite/client: /// /// # Vue

Vite 为 Vue 提供第一优先级支持:

Vue 3 单文件组件支持:@vitejs/plugin-vue (opens new window) Vue 3 JSX 支持:@vitejs/plugin-vue-jsx (opens new window) Vue 2.7 支持:vitejs/vite-plugin-vue2 (opens new window) Vue applyColor import { applyColor } from './example.module.css' document.getElementById('foo').className = applyColor # CSS 预处理器

由于 Vite 的目标仅为现代浏览器,因此建议使用原生 CSS 变量和实现 CSSWG 草案的 PostCSS 插件(例如 postcss-nesting )来编写简单的、符合未来标准的 CSS。

话虽如此,但 Vite 也同时提供了对 .scss, .sass, .less, .styl和 .stylus文件的内置支持。没有必要为它们安装特定的 Vite 插件,但必须安装相应的预处理器依赖:

# .scss and .sass npm add -D sass # .less npm add -D less # .styl and .stylus npm add -D stylus

如果使用的是单文件组件,可以通过 (或其他预处理器)自动开启。

Vite 为 Sass 和 Less 改进了 @import解析,以保证 Vite 别名也能被使用。另外,url()中的相对路径引用的,与根文件不同目录中的 Sass/Less 文件会自动变基以保证正确性。

由于 Stylus API 限制,@import别名和 URL 变基不支持 Stylus。

你还可以通过在文件扩展名前加上 .module来结合使用 CSS modules 和预处理器,例如 style.module.scss。

# 禁用 CSS 注入页面

自动注入 CSS 内容的行为可以通过 ?inline参数来关闭。在关闭时,被处理过的 CSS 字符串将会作为该模块的默认导出,但样式并没有被注入到页面中。

import styles from './foo.css' // 样式将会注入页面 import otherStyles from './bar.css?inline' // 样式不会注入页面 # 静态资源处理

导入一个静态资源会返回解析后的 URL:

import imgUrl from './img.png' document.getElementById('hero-img').src = imgUrl

添加一些特殊的查询参数可以更改资源被引入的方式:

// 显式加载资源为一个 URL import assetAsURL from './asset.js?url' // 以字符串形式加载资源 import assetAsString from './shader.glsl?raw' // 加载为 Web Worker import Worker from './worker.js?worker' // 在构建时 Web Worker 内联为 base64 字符串 import InlineWorker from './worker.js?worker&inline'

更多细节请见 静态资源处理 。

# JSON

JSON 可以被直接导入 —— 同样支持具名导入:

// 导入整个对象 import json from './example.json' // 对一个根字段使用具名导入 —— 有效帮助 treeshaking! import { field } from './example.json' # Glob 导入

Vite 支持使用特殊的 importa.glob函数从文件系统导入多个模块:

const modules = importa.glob('./dir/*.js')

以上将会被转译为下面的样子:

// vite 生成的代码 const modules = { './dir/foo.js': () => import('./dir/foo.js'), './dir/bar.js': () => import('./dir/bar.js'), }

你可以遍历 modules对象的 key 值来访问相应的模块:

for (const path in modules) { modules`path` => { console.log(path, mod) }) }

匹配到的文件默认是懒加载的,通过动态导入实现,并会在构建时分离为独立的 chunk。如果你倾向于直接引入所有的模块(例如依赖于这些模块中的副作用首先被应用),你可以传入 { eager: true }作为第二个参数:

const modules = importa.glob('./dir/*.js', { eager: true })

以上会被转译为下面的样子:

// vite 生成的代码 import * as __glob__0_0 from './dir/foo.js' import * as __glob__0_1 from './dir/bar.js' const modules = { './dir/foo.js': __glob__0_0, './dir/bar.js': __glob__0_1, } # Glob 导入形式

importa.glob都支持以字符串形式导入文件,类似于 以字符串形式导入资源 。在这里,我们使用了 Import Reflection 语法对导入进行断言:

const modules = importa.glob('./dir/*.js', { as: 'raw' })

上面的代码会被转换为下面这样:

// code produced by vite(代码由 vite 输出) const modules = { './dir/foo.js': 'export default "foo"\n', './dir/bar.js': 'export default "bar"\n', }

{ as: 'url' }还支持将资源作为 URL 加载。

# 多个匹配模式

第一个参数可以是一个 glob 数组,例如:

const modules = importa.glob(['./dir/*.js', './another/*.js']) # 反面匹配模式

同样也支持反面 glob 匹配模式(以 !作为前缀)。若要忽略结果中的一些文件,你可以添加“排除匹配模式”作为第一个参数:

const modules = importa.glob(['./dir/*.js', '!**/bar.js']) // vite 生成的代码 const modules = { './dir/foo.js': () => import('./dir/foo.js'), } # 具名导入

也可能你只想要导入模块中的部分内容,那么可以利用 import选项。

const modules = importa.glob('./dir/*.js', { import: 'setup' }) // vite 生成的代码 const modules = { './dir/foo.js': () => import('./dir/foo.js').then((m) => m.setup), './dir/bar.js': () => import('./dir/bar.js').then((m) => m.setup), }

当与 eager一同存在时,甚至可以对这些模块进行 tree-shaking。

const modules = importa.glob('./dir/*.js', { import: 'setup', eager: true }) // vite 生成的代码 import { setup as __glob__0_0 } from './dir/foo.js' import { setup as __glob__0_1 } from './dir/bar.js' const modules = { './dir/foo.js': __glob__0_0, './dir/bar.js': __glob__0_1, }

设置 import为 default可以加载默认导出。

const modules = importa.glob('./dir/*.js', { import: 'default', eager: true, }) // vite 生成的代码 import __glob__0_0 from './dir/foo.js' import __glob__0_1 from './dir/bar.js' const modules = { './dir/foo.js': __glob__0_0, './dir/bar.js': __glob__0_1, } # 自定义查询

你也可以使用 query选项来提供对导入的自定义查询,以供其他插件使用。

const modules = importa.glob('./dir/*.js', { query: { foo: 'bar', bar: true }, }) // vite 生成的代码 const modules = { './dir/foo.js': () => import('./dir/foo.js?foo=bar&bar=true'), './dir/bar.js': () => import('./dir/bar.js?foo=bar&bar=true'), } # Glob 导入注意事项

请注意:

这只是一个 Vite 独有的功能而不是一个 Web 或 ES 标准 该 Glob 模式会被当成导入标识符:必须是相对路径(以 ./开头)或绝对路径(以 /开头,相对于项目根目录解析)或一个别名路径(请看 resolve.alias 选项 )。 Glob 匹配是使用 fast-glob 来实现的 —— 阅读它的文档来查阅 支持的 Glob 模式 。 你还需注意,所有 importa.glob的参数都必须以字面量传入。你 不可以在其中使用变量或表达式。 # 动态导入

和 glob 导入 类似,Vite 也支持带变量的动态导入。

const module = await import(`./dir/${file}.js`)

注意变量仅代表一层深的文件名。如果 file是 foo/bar,导入将会失败。对于更进阶的使用详情,你可以使用 glob 导入 功能。

# WebAssembly

预编译的 .wasm文件可以通过 ?init来导入。默认导出一个初始化函数,返回值为所导出 wasm 实例对象的 Promise:

import init from './example.wasm?init' init().then((instance) => { instance.exports.test() })

init函数还可以将传递给 WebAssembly.instantiate的导入对象作为其第二个参数:

init({ imports: { someFunc: () => { /* ... */ }, }, }).then(() => { /* ... */ })

在生产构建当中,体积小于 assetInlineLimit的 .wasm文件将会被内联为 base64 字符串。否则,它们将作为资源复制到 dist目录中,并按需获取。

WARNING

对 WebAssembly 的 ES 模块集成提案 尚未支持。 请使用 vite-plugin-wasm 或其他社区上的插件来处理。

# Web Workers # 通过构造器导入

一个 Web Worker 可以使用 new Worker() 和 new SharedWorker() 导入。与 worker 后缀相比,这种语法更接近于标准,是创建 worker 的 推荐方式。

const worker = new Worker(new URL('./worker.js', importa.url))

worker 构造函数会接受可以用来创建 “模块” worker 的选项:

const worker = new Worker(new URL('./worker.js', importa.url), { type: 'module', }) # 带有查询后缀的导入

你可以在导入请求上添加 ?worker或 ?sharedworker查询参数来直接导入一个 web worker 脚本。默认导出会是一个自定义 worker 的构造函数:

import MyWorker from './worker?worker' const worker = new MyWorker()

Worker 脚本也可以使用 import语句来替代 importScripts()—— 注意,在开发过程中,这依赖于浏览器原生支持,目前只在 Chrome 中适用,而在生产版本中,它已经被编译掉了。

默认情况下,worker 脚本将在生产构建中编译成单独的 chunk。如果你想将 worker 内联为 base64 字符串,请添加 inline查询参数:

import MyWorker from './worker?worker&inline'

如果你想要以一个 URL 的形式读取该 worker,请添加 url这个 query:

import MyWorker from './worker?worker&url'

关于如何配置打包全部 worker,可以查看 Worker 选项 了解更多相关细节。

# 构建优化

下面所罗列的功能会自动应用为构建过程的一部分,除非你想禁用它们,否则没有必要显式配置。

# CSS 代码分割

Vite 会自动地将一个异步 chunk 模块中使用到的 CSS 代码抽取出来并为其生成一个单独的文件。这个 CSS 文件将在该异步 chunk 加载完成时自动通过一个 标签载入,该异步 chunk 会保证只在 CSS 加载完毕后再执行,避免发生 FOUC 。

如果你更倾向于将所有的 CSS 抽取到一个文件中,你可以通过设置 build.cssCodeSplit 为 false来禁用 CSS 代码分割。

# 预加载指令生成

Vite 会为入口 chunk 和它们在打包出的 HTML 中的直接引入自动生成 指令。

# 异步 Chunk 加载优化

在实际项目中,Rollup 通常会生成 “共用” chunk —— 被两个或以上的其他 chunk 共享的 chunk。与动态导入相结合,会很容易出现下面这种场景:

在无优化的情境下,当异步 chunk A 被导入时,浏览器将必须请求和解析 A,然后它才能弄清楚它也需要共用 chunk C。这会导致额外的网络往返:

Entry ---> A ---> C

Vite 将使用一个预加载步骤自动重写代码,来分割动态导入调用,以实现当 A被请求时,C也将 同时被请求:

Entry ---> (A + C)

C也可能有更深的导入,在未优化的场景中,这会导致更多的网络往返。Vite 的优化会跟踪所有的直接导入,无论导入的深度如何,都能够完全消除不必要的往返。

Last Updated: 3/8/2023, 8:47:01 AM

← 开始 命令行界面 →



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有